home *** CD-ROM | disk | FTP | other *** search
Wrap
/* macam - webcam app and QuickTime driver component Copyright (C) 2002 Matthias Krauss (macam@matthias-krauss.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA $Id: MyCameraCentral.m,v 1.28 2005/11/14 20:46:32 hxr Exp $ */ #include <CoreFoundation/CoreFoundation.h> #include <IOKit/IOKitLib.h> #include <IOKit/IOMessage.h> #include <IOKit/IOCFPlugIn.h> #include <IOKit/usb/IOUSBLib.h> #include "MiscTools.h" #import "MyCameraInfo.h" #import "MyCameraCentral.h" #import "MyCameraDriver.h" #import "MyKiaraFamilyDriver.h" #import "MyKiaraFlippedDriver.h" #import "MyTimonFamilyDriver.h" #import "MyCPIACameraDriver.h" #import "MyQX3Driver.h" #import "MySTV680Driver.h" #import "MyIntelPCCameraPro.h" #import "MyDummyCameraDriver.h" #import "MyQCExpressADriver.h" #import "MyQCExpressBDriver.h" #import "MyQCWebDriver.h" #import "MyVicamDriver.h" #import "MySPCA504Driver.h" #import "MyOV511Driver.h" #import "MySonix2028Driver.h" #import "MySE401Driver.h" #import "MyQCProBeigeDriver.h" #import "MySPCA500Driver.h" #import "MyQCOrbitDriver.h" #import "SQ905.h" #include "unistd.h" void DeviceAdded(void *refCon, io_iterator_t iterator); static NSString* driverBundleName=@"net.sourceforge.webcam-osx.common"; static NSMutableDictionary* prefsDict=NULL; MyCameraCentral* sharedCameraCentral=NULL; @interface MyCameraCentral (Private) //Internal preferences handling. We cannot use NSUserDefaults here because we might be in someone else's bundle (in a lib) - (id) prefsForKey:(NSString*) key; - (void) setPrefs:(id)prefs forKey:(NSString*)key; - (void) registerCameraDriver:(Class)driver; - (CameraError) locationIdOfUSBDeviceRef:(io_service_t)usbDeviceRef to:(UInt32*)outVal; @end @implementation MyCameraCentral //MyCameraCentral is a singleton. Use this function to get the shared instance + (MyCameraCentral*) sharedCameraCentral { if (!sharedCameraCentral) sharedCameraCentral=[[MyCameraCentral alloc] init]; return sharedCameraCentral; } //See if someone has requested MyCameraCentral before + (BOOL) isCameraCentralExisting { return (sharedCameraCentral!=NULL)?YES:NO; } //Localization for driver-specific stuff. As a component, the standard stuff won't work... + (NSString*) localizedStringFor:(NSString*) str { NSBundle* bundle=[NSBundle bundleForClass:[self class]]; NSString* ret=[bundle localizedStringForKey:str value:@"" table:@"DriverLocalizable"]; return ret; } + (void) localizedCStrFor:(char*)cKey into:(char*)cValue { NSAutoreleasePool* pool; NSString* string; const char* tmpCStr; if (!cValue) return; if (!cKey) return; pool=[[NSAutoreleasePool alloc] init]; string=[NSString stringWithCString:cKey]; string=[self localizedStringFor:string]; tmpCStr=[string lossyCString]; CStr2CStr(tmpCStr,cValue); //Note: No bounds check! Don't write dramas... [pool release]; } - (char*) localizedCStrForError:(CameraError)err { char* cstr; switch (err) { case CameraErrorOK: case CameraErrorBusy: case CameraErrorNoPower: case CameraErrorNoCam: case CameraErrorNoMem: case CameraErrorNoBandwidth: case CameraErrorTimeout: case CameraErrorUSBProblem: case CameraErrorInternal: cstr=localizedErrorCStrs[err]; break; default: cstr=localizedUnknownErrorCStr; break; } return cstr; } //Init, startup, shutdown, dealloc - (id) init { [super init]; cameraTypes=[[NSMutableArray alloc] initWithCapacity:10]; cameras=[[NSMutableArray alloc] initWithCapacity:10]; delegate=NULL; //Cache localized error codes [[self class] localizedCStrFor:"CameraErrorOK" into:localizedErrorCStrs[CameraErrorOK]]; [[self class] localizedCStrFor:"CameraErrorBusy" into:localizedErrorCStrs[CameraErrorBusy]]; [[self class] localizedCStrFor:"CameraErrorNoPower" into:localizedErrorCStrs[CameraErrorNoPower]]; [[self class] localizedCStrFor:"CameraErrorNoCam" into:localizedErrorCStrs[CameraErrorNoCam]]; [[self class] localizedCStrFor:"CameraErrorNoMem" into:localizedErrorCStrs[CameraErrorNoMem]]; [[self class] localizedCStrFor:"CameraErrorNoBandwidth" into:localizedErrorCStrs[CameraErrorNoBandwidth]]; [[self class] localizedCStrFor:"CameraErrorTimeout" into:localizedErrorCStrs[CameraErrorTimeout]]; [[self class] localizedCStrFor:"CameraErrorUSBProblem" into:localizedErrorCStrs[CameraErrorUSBProblem]]; [[self class] localizedCStrFor:"CameraErrorUnimplemented" into:localizedErrorCStrs[CameraErrorUnimplemented]]; [[self class] localizedCStrFor:"CameraErrorInternal" into:localizedErrorCStrs[CameraErrorInternal]]; [[self class] localizedCStrFor:"UnknownError" into:localizedUnknownErrorCStr]; return self; } - (void) dealloc { [self shutdown]; //Make sure everything's shut down if (cameraTypes!=NULL) [cameraTypes release]; cameraTypes=NULL; if (cameras!=NULL) [cameras release]; cameras=NULL; [super dealloc]; // where is the constructor? } - (BOOL) startupWithNotificationsOnMainThread:(BOOL)nomt recognizeLaterPlugins:(BOOL)rlp{ MyCameraInfo* info=NULL; long i; long numTestCameras=0; id obj=NULL; mach_port_t masterPort; CFMutableDictionaryRef matchingDict; CFRunLoopSourceRef runLoopSource; CFNumberRef numberRef; kern_return_t ret; SInt32 usbVendor; SInt32 usbProduct; io_iterator_t iterator; NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init]; assert(cameraTypes); assert(cameras); doNotificationsOnMainThread=nomt; recognizeLaterPlugins=rlp; //Add Driver classes (this is where we have to add new model classes!) [self registerCameraDriver:[MySPCA500Driver class]]; [self registerCameraDriver:[MyAiptekPocketDV class]]; [self registerCameraDriver:[MyKiaraFamilyDriver class]]; [self registerCameraDriver:[MyKiaraFlippedDriver class]]; [self registerCameraDriver:[MyTimonFamilyDriver class]]; [self registerCameraDriver:[MyCPIACameraDriver class]]; [self registerCameraDriver:[MyQX3Driver class]]; [self registerCameraDriver:[MyQX5Driver class]]; [self registerCameraDriver:[MySTV680Driver class]]; [self registerCameraDriver:[MyQCExpressADriver class]]; [self registerCameraDriver:[MyQCExpressBDriver class]]; [self registerCameraDriver:[MyQCWebDriver class]]; [self registerCameraDriver:[MyVicamDriver class]]; [self registerCameraDriver:[MySPCA504Driver class]]; [self registerCameraDriver:[MyOV511Driver class]]; [self registerCameraDriver:[MyOV511PlusDriver class]]; [self registerCameraDriver:[MySonix2028Driver class]]; [self registerCameraDriver:[MyViviCam3350BDriver class]]; [self registerCameraDriver:[MySwedaSSP09BDriver class]]; [self registerCameraDriver:[MySE401Driver class]]; [self registerCameraDriver:[MyQCProBeigeDriver class]]; [self registerCameraDriver:[MyQCVCDriver class]]; [self registerCameraDriver:[MyQCOrbitDriver class]]; [self registerCameraDriver:[SQ905 class]]; // [self registerCameraDriver:[MyIntelPCCameraPro class]]; // [self registerCameraDriver:[MyIntelPCCamera class]]; // [self registerCameraDriver:[MyGrandtecVcap class]]; // [self registerCameraDriver:[MyViewQuestM318B class]]; // [self registerCameraDriver:[MyViewQuestVQ110 class]]; // [self registerCameraDriver:[MyDVC325 class]]; //Get the IOKit master port (needed for communication with IOKit) ret = IOMasterPort(MACH_PORT_NULL, &masterPort); if (ret||(!masterPort)) { NSLog(@"MyCameraCentral: IOMasterPort failed (%08x)", ret); return NO;} //Get a notification port, get its event source and connect it to the current thread notifyPort = IONotificationPortCreate(masterPort); runLoopSource = IONotificationPortGetRunLoopSource(notifyPort); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode); //Go through all our drivers and add plug-in notifications for them for (i=0;i<[cameraTypes count];i++) { //Get info about the current camera info=[cameraTypes objectAtIndex:i]; if (info==NULL) { NSLog(@"MyCameraCentral:wiringThread: bad info"); return NO; } usbVendor =[info vendorID]; usbProduct=[info productID]; // Set up the matching criteria for the devices we're interested in matchingDict = IOServiceMatching(kIOUSBDeviceClassName); if (!matchingDict) { NSLog(@"MyCameraCentral:IOServiceMatching failed"); return NO; } // Add our vendor and product IDs to the matching criteria numberRef = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&usbVendor); CFDictionarySetValue(matchingDict,CFSTR(kUSBVendorID),numberRef); CFRelease(numberRef); numberRef=NULL; numberRef = CFNumberCreate(kCFAllocatorDefault,kCFNumberSInt32Type,&usbProduct); CFDictionarySetValue(matchingDict,CFSTR(kUSBProductID),numberRef); CFRelease(numberRef); numberRef=NULL; if (recognizeLaterPlugins) { //Request notification if matching devices are plugged in or... ret = IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, matchingDict, DeviceAdded, info, &iterator); } else { //... just get the currently connected devices ret = IOServiceGetMatchingServices(masterPort, matchingDict, &iterator); } if (ret==0) { //Get first devices and trigger notification process DeviceAdded(info, iterator); //If we don't later notifications, we can release the enumerator if (!recognizeLaterPlugins) { IOObjectRelease(iterator); } } } //Try to find out how many test cameras we have obj=[self prefsForKey:@"Dummy cameras"]; if (obj) numTestCameras=[obj longValue]; else numTestCameras=0; //Add the dummy test image cameras to the list of available cameras for (i=0;i<numTestCameras;i++) { info=[[MyCameraInfo alloc] init]; [info setDriverClass:[MyDummyCameraDriver class]]; [info setProductID:[MyDummyCameraDriver cameraUsbProductID]]; [info setVendorID:[MyDummyCameraDriver cameraUsbVendorID]]; [info setCameraName: [NSString stringWithFormat:@"%@ #%i", [MyDummyCameraDriver cameraName], i+1]]; [info setCentral: self]; [cameras addObject:info]; } [pool release]; return YES; } - (void) shutdown { MyCameraInfo* info; NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init]; //Get a pool to catch the remaining drivers //shutdown all cameras while ([cameras count]>0) { info=[cameras lastObject]; [cameras removeLastObject]; //disconnect from the driver and autorelease our retain if ([info driver]!=NULL) { [[info driver] setCentral:NULL]; [[info driver] shutdown]; } [info release]; } //This would be a great place to release all USB notifications ***** //release cameryTypes cameraInfos while ([cameraTypes count]>0) { info=[cameraTypes lastObject]; [cameraTypes removeLastObject]; [info release]; } [pool release]; } - (id) delegate { return delegate; } - (void) setDelegate:(id)d { delegate=d; } - (BOOL) doNotificationsOnMainThread { return doNotificationsOnMainThread; } - (short) numCameras { return [cameras count]; } - (short) indexOfCamera:(MyCameraDriver*)driver { short i=0; while (i<[cameras count]) { if ([[cameras objectAtIndex:i] driver]==driver) return i; else i++; } return -1; } - (unsigned long) idOfCameraWithIndex:(short)idx { if ((idx<0)||(idx>=[self numCameras])) return 0; return [[cameras objectAtIndex:idx] cid]; } - (unsigned long) idOfCameraWithLocationID:(UInt32)locID { short i; for (i=0;i<[cameras count];i++) { if ([[cameras objectAtIndex:i] locationID]==locID) return [[cameras objectAtIndex:i] cid]; } return 0; } - (CameraError) useCameraWithID:(unsigned long)cid to:(MyCameraDriver**)outCam acceptDummy:(BOOL)acceptDummy { long l; MyCameraInfo* dev=NULL; MyCameraDriver* cam=NULL; CameraError err=CameraErrorOK; if (outCam) *outCam=NULL; for (l=0;(l<[cameras count])&&(dev==NULL);l++) { dev=[cameras objectAtIndex:l]; if ([dev cid]!=cid) dev=NULL; } if (dev==NULL) { #ifdef VERBOSE NSLog(@"MyCameraCentral: cid not found"); #endif err=CameraErrorInternal; } if (!err) { if ([dev driver]) err=CameraErrorBusy; } if (!err) { cam=[[[dev driverClass] alloc] initWithCentral:self]; if (!cam) { #ifdef VERBOSE NSLog(@"MyCameraCentral: could not instantiate driver"); #endif err=CameraErrorNoMem; } } if (!err) { [cam setDelegate:delegate]; err=[cam startupWithUsbLocationId:[dev locationID]]; if (err!=CameraErrorOK) { [cam release]; cam=NULL; } } if (err&&acceptDummy) { //We have an error and the sender wants a dummy in case of an error cam=[self useDummyForError:err]; } if (cam!=NULL) { [dev setDriver:cam]; [cam setCameraInfo:dev]; [self setCameraToDefaults:cam]; if (outCam) *outCam=cam; } return err; } - (MyCameraDriver*) useDummyForError:(CameraError)err { MyCameraDriver* driver=[[MyDummyCameraDriver alloc] initWithError:err central:self]; if (driver) { [driver setDelegate:delegate]; [driver startupWithUsbLocationId:0]; } return driver; } - (NSString*) nameForID:(unsigned long)cid { long l=0; while (l<[cameras count]) { if ([[cameras objectAtIndex:l] cid]==cid) { return [[cameras objectAtIndex:l] cameraName]; } else { l++; } } return NULL; } - (NSString*) nameForDriver:(MyCameraDriver*)driver { long l=0; while (l<[cameras count]) { if ([[cameras objectAtIndex:l] driver]==driver) { return [[cameras objectAtIndex:l] cameraName]; } else l++; } return NULL; } - (BOOL) getName:(char*)name forID:(unsigned long)cid { NSString* camName=[self nameForID:cid]; if (!camName) return NO; [camName getCString:name]; return YES; } - (BOOL) getName:(char*)name forDriver:(MyCameraDriver*)driver { NSString* camName=[self nameForDriver:driver]; if (!camName) return NO; [camName getCString:name]; return YES; } /*These functions read and write the camera settings. We cannot use the direct user defaults mechanism because we're sometimes a client in another app and we don't want to mess up the app's preferences. So we use the lower-level persistentDomainForName mechanism. */ - (BOOL) setCameraToDefaults:(MyCameraDriver*) cam { NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init]; BOOL ok=YES; short idx; unsigned long cid; NSDictionary* camDict; if (ok) { if (!cam) ok=NO; } if (ok) { idx=[self indexOfCamera:cam]; if (idx<0) ok=NO; //This camera is not listed as connected } if (ok) { cid=[self idOfCameraWithIndex:idx]; if (cid<1) ok=NO; //This camera has no cid (should not happen ever) } if (ok) { //We use the driver class instead of the camera name to prevent differences due to localization camDict=[self prefsForKey:NSStringFromClass([[cameras objectAtIndex:idx] driverClass])]; if (!camDict) ok=NO; //There are no defaults for the camera listed } if (ok) { if ([camDict objectForKey:@"brightness"]) [cam setBrightness:[[camDict objectForKey:@"brightness"] floatValue]]; if ([camDict objectForKey:@"contrast"]) [cam setContrast:[[camDict objectForKey:@"contrast"] floatValue]]; if ([camDict objectForKey:@"saturation"]) [cam setSaturation:[[camDict objectForKey:@"saturation"] floatValue]]; if ([camDict objectForKey:@"gamma"]) [cam setGamma:[[camDict objectForKey:@"gamma"] floatValue]]; if ([camDict objectForKey:@"sharpness"]) [cam setSharpness:[[camDict objectForKey:@"sharpness"] floatValue]]; if ([camDict objectForKey:@"gain"]) [cam setGain:[[camDict objectForKey:@"gain"] floatValue]]; if ([camDict objectForKey:@"shutter"]) [cam setShutter:[[camDict objectForKey:@"shutter"] floatValue]]; if ([camDict objectForKey:@"autogain"]) [cam setAutoGain:[[camDict objectForKey:@"autogain"] boolValue]]; if ([camDict objectForKey:@"hflip"]) [cam setHFlip:[[camDict objectForKey:@"hflip"] boolValue]]; if ([camDict objectForKey:@"compression"]) [cam setCompression:[[camDict objectForKey:@"compression"] shortValue]]; if ([camDict objectForKey:@"resolution"]&&[camDict objectForKey:@"fps"]) [cam setResolution:[[camDict objectForKey:@"resolution"] shortValue] fps:[[camDict objectForKey:@"fps"] shortValue]]; if ([camDict objectForKey:@"white balance"]) [cam setWhiteBalanceMode:(WhiteBalanceMode)[[camDict objectForKey:@"white balance"] shortValue]]; } [pool release]; return ok; } - (BOOL) saveCameraSettingsAsDefaults:(MyCameraDriver*) cam { NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init]; BOOL ok=YES; short idx; unsigned long cid; NSMutableDictionary* camDict; if (ok) { if (!cam) ok=NO; } if (ok) { idx=[self indexOfCamera:cam]; if (idx<0) ok=NO; //This camera is not listed as connected } if (ok) { cid=[self idOfCameraWithIndex:idx]; if (cid<1) ok=NO; //This camera has no cid (should not happen ever) } if (ok) { camDict=[NSMutableDictionary dictionaryWithCapacity:11]; if (!camDict) ok=NO; } if (ok) { if ([cam canSetBrightness]) [camDict setObject:[NSNumber numberWithFloat:[cam brightness]] forKey:@"brightness"]; if ([cam canSetContrast]) [camDict setObject:[NSNumber numberWithFloat:[cam contrast]] forKey:@"contrast"]; if ([cam canSetSaturation]) [camDict setObject:[NSNumber numberWithFloat:[cam saturation]] forKey:@"saturation"]; if ([cam canSetGamma]) [camDict setObject:[NSNumber numberWithFloat:[cam gamma]] forKey:@"gamma"]; if ([cam canSetSharpness]) [camDict setObject:[NSNumber numberWithFloat:[cam sharpness]] forKey:@"sharpness"]; if ([cam canSetGain]) [camDict setObject:[NSNumber numberWithFloat:[cam gain]] forKey:@"gain"]; if ([cam canSetShutter]) [camDict setObject:[NSNumber numberWithFloat:[cam shutter]] forKey:@"shutter"]; if ([cam canSetAutoGain]) [camDict setObject:[NSNumber numberWithBool:[cam isAutoGain]] forKey:@"autogain"]; if ([cam canSetHFlip]) [camDict setObject:[NSNumber numberWithBool:[cam hFlip]] forKey:@"hflip"]; if ([cam maxCompression]>0) [camDict setObject:[NSNumber numberWithShort:[cam compression]] forKey:@"compression"]; if ([cam canSetWhiteBalanceMode]) [camDict setObject:[NSNumber numberWithShort:(short)[cam whiteBalanceMode]] forKey:@"white balance"]; [camDict setObject:[NSNumber numberWithShort:[cam resolution]] forKey:@"resolution"]; [camDict setObject:[NSNumber numberWithShort:[cam fps]] forKey:@"fps"]; //We use the driver class instead of the camera name to prevent differences due to localization [self setPrefs:camDict forKey:NSStringFromClass([[cameras objectAtIndex:idx] driverClass])]; } [pool release]; return ok; } void DeviceRemoved( void *refCon,io_service_t service,natural_t messageType,void *messageArgument ) { MyCameraInfo* dev=(MyCameraInfo*)refCon; if (messageType!=kIOMessageServiceIsTerminated) return; if (dev==NULL) { #ifdef VERBOSE NSLog(@"MaCameraCentral:DeviceRemoved: bad refCon"); #endif } else { if ([dev driver]) [[dev driver] stopUsingUSB]; //Pass the info to the driver as fast as possible [[dev central] deviceRemoved:[dev cid]]; } } - (void) deviceRemoved:(unsigned long)cid { kern_return_t ret; long l; MyCameraInfo* dev=NULL; //remove the device in the cameras list for (l=0;l<[cameras count];l++) { if ([[cameras objectAtIndex:l] cid]==cid) { dev=[cameras objectAtIndex:l]; [cameras removeObjectAtIndex:l]; } } if (!dev) { #ifdef VERBOSE NSLog(@"MyCameraInfo:deviceRemoved: Tried to unregister a device not registered"); #endif return; //We didn't find the camera } //Release the usb stuff ret = IOObjectRelease([dev notification]); //we don't need the usb notification any more //Initiate the driver shutdown. if ([dev driver]!=NULL) { [[dev driver] shutdown]; //We don't release it here - it is done in the cameraHasShutDown notification [dev release]; //we still own it since we did not autorelease in [cameraAdded] } } void DeviceAdded(void *refCon, io_iterator_t iterator) { MyCameraInfo* info=(MyCameraInfo*)refCon; if (info!=NULL) { [[info central] deviceAdded:iterator info:info]; } } - (void) deviceAdded:(io_iterator_t)iterator info:(MyCameraInfo*)type { kern_return_t ret; io_service_t usbDeviceRef; MyCameraInfo* dev; io_object_t notification; while (usbDeviceRef = IOIteratorNext(iterator)) { UInt32 locID; //Setup our data object we use to track the device while it is plugged dev=[type copy]; if (!dev) { #ifdef VERBOSE NSLog(@"Could not copy MyCameraInfo object on insertion of a device"); #endif continue; } //Request notification if the device is unplugged ret = IOServiceAddInterestNotification(notifyPort, usbDeviceRef, kIOGeneralInterest, DeviceRemoved, dev, ¬ification); if (ret!=KERN_SUCCESS) { #ifdef VERBOSE NSLog(@"IOServiceAddInterestNotification returned %08x\n",ret); #endif [dev release]; continue; } //Try to find our USB location ID if ([self locationIdOfUSBDeviceRef:usbDeviceRef to:&locID]!=CameraErrorOK) { #ifdef VERBOSE NSLog(@"failed to get location id"); #endif [dev release]; continue; } //Remember the notification (we have to release it later) [dev setNotification:notification]; [dev setLocationID:locID]; //Put the new entry to the list of available cameras [cameras addObject:dev]; //Spread the news that a camera was plugged in [self cameraDetected:[dev cid]]; } } - (void) cameraDetected:(unsigned long) cid { if (delegate) { if ([delegate respondsToSelector:@selector(cameraDetected:)]) { [delegate cameraDetected:cid]; } } } - (void) cameraHasShutDown:(id)sender { long i; MyCameraInfo* info; for(i=0;i<[cameras count];i++) { info=[cameras objectAtIndex:i]; if ([info driver]==sender) { [info setDriver:NULL]; //If it's still in the list: mark it as available } } [sender autorelease]; //We clear our reference to that driver. When we receive this, we have built it. } - (id) prefsForKey:(NSString*) key { id val=NULL; if (!key) return NULL; //No key, no value if (!prefsDict) { //No prefs there. Try to load prefs file. NSString* pathName=[[NSString stringWithFormat:@"~/Library/Preferences/%@.plist",driverBundleName] stringByExpandingTildeInPath]; NSDictionary* dict; dict=[NSDictionary dictionaryWithContentsOfFile:pathName]; if (dict) prefsDict=[dict mutableCopy]; } if (!prefsDict) { //No file there. Try to open a new one prefsDict=[[NSMutableDictionary alloc] initWithCapacity:3]; } if (!prefsDict) return NULL; //Still no prefs dict there - give up val=[prefsDict objectForKey:key]; if (!val) return NULL; //No value for that key val=[val copy]; if (!val) return NULL; //Probably no mem or some non-copying object (could that happen? I guess not) [val autorelease]; return val; } - (void) setPrefs:(id)value forKey:(NSString*)key { NSString* pathName; if (!key) return; //No key, no change [self prefsForKey:key]; //Ensure the prefs are loaded if (!prefsDict) return; //Still no prefs? Give up. //Do the change if (value) { [prefsDict setObject:[[value copy] autorelease] forKey:key]; } else { [prefsDict removeObjectForKey:key]; } //Write to file pathName=[[NSString stringWithFormat:@"~/Library/Preferences/%@.plist",driverBundleName] stringByExpandingTildeInPath]; [prefsDict writeToFile:pathName atomically:YES]; } - (void) registerCameraDriver:(Class)driver { NSArray* arr=[driver cameraUsbDescriptions]; int i; for (i=0;i<[arr count];i++) { NSDictionary* dict=[arr objectAtIndex:i]; MyCameraInfo* info=[[MyCameraInfo alloc] init]; if (info!=NULL) { [info setCameraName:[dict objectForKey:@"name"]]; [info setVendorID:[[dict objectForKey:@"idVendor"] unsignedShortValue]]; [info setProductID:[[dict objectForKey:@"idProduct"] unsignedShortValue]]; [info setDriverClass:driver]; [info setCentral: self]; [cameraTypes addObject:info]; } } } - (CameraError) locationIdOfUSBDeviceRef:(io_service_t)usbDeviceRef to:(UInt32*)outVal { UInt32 locID=0; kern_return_t kernelErr; SInt32 score; IOCFPlugInInterface **plugin=NULL; CameraError err=CameraErrorOK; HRESULT res; IOUSBDeviceInterface** dev=NULL; kernelErr = IOCreatePlugInInterfaceForService(usbDeviceRef, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, &score); if ((kernelErr!=kIOReturnSuccess)||(!plugin)) { #ifdef VERBOSE NSLog(@"MyCameraCentral: IOCreatePlugInInterfaceForService; Could not get plugin"); #endif return CameraErrorUSBProblem; } if (!err) { res=(*plugin)->QueryInterface(plugin,CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID),(LPVOID*)(&dev)); (*plugin)->Release(plugin); plugin=NULL; if ((res)||(!dev)) { #ifdef VERBOSE NSLog(@"MyCameraCentral: IOCreatePlugInInterfaceForService; Could not get device interface"); #endif err=CameraErrorUSBProblem; } } if (!err) { kernelErr = (*dev)->GetLocationID(dev,&locID); (*dev)->Release(dev); if (kernelErr!=KERN_SUCCESS) { #ifdef VERBOSE NSLog(@"MyCameraCentral: IOCreatePlugInInterfaceForService; Could not get Location ID"); #endif err=CameraErrorUSBProblem; } } if (outVal) { if (!err) *outVal=locID; else *outVal=0; } return err; } @end